// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: regularExpression.h,v 1.1 2008/06/24 02:08:56 xyzhang Exp $
//

#ifndef BALL_DATATYPE_REGULAREXPRESSION_H
#define BALL_DATATYPE_REGULAREXPRESSION_H

#include "ballview_common.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include <vector>

#include "ballview_string.h"

using std::vector;

#define BALL_REGULAR_EXPRESSION_DEFAULT_PATTERN   ""

namespace BALL {
	/**	Regular expression class
	\ingroup  DatatypeMiscellaneous
	*/
	class RegularExpression {
	public:

		// BALL_CREATE(RegularExpression)

		/**	@name	String constants 
		*/
		//@{

		/**	alphabetic letters.
		*/
		static const String ALPHA;

		/**	alphanumeric letters
		*/
		static const String ALPHANUMERIC;

		/**	real numbers
		*/
		static const String REAL;

		/** identifier characters
		*/
		static const String IDENTIFIER;

		/** integer characters
		*/
		static const String INTEGER;

		/** hexadecimal and integer characters
		*/
		static const String HEXADECIMAL_INTEGER;

		/** lowercase letters
		*/
		static const String LOWERCASE;

		/** non alphabetic characters
		*/
		static const String NON_ALPHA;

		/** non alphanumeric characters
		*/
		static const String NON_ALPHANUMERIC;

		/** non numeric characters
		*/
		static const String NON_NUMERIC;

		/** non whitespace charcters
		*/
		static const String NON_WHITESPACE;

		/**	uppercase letters.
		*/
		static const String UPPERCASE;

		/** whitespace characters.
		*/
		static const String WHITESPACE;
		//@}

		/**	@name	Constructors and Destructors 
		*/
		//@{

		///	Default constructor
		RegularExpression();

		///	Copy constructor
		RegularExpression(const RegularExpression& regular_expression);

		///
		RegularExpression(const String& pattern, bool wildcard_pattern = false);

		///	Destructor
		virtual ~RegularExpression();

		///	Reset the object attributes to their default values
		virtual void clear();

		///	Destroy the instance
		void destroy();
		//@}

		/**	@name	Assignment
		*/
		//@{

		/// Assignment operator
		RegularExpression& operator = (const RegularExpression& expression);

		///	Assign from another instance
		void set(const RegularExpression& regular_expression);

		///	Assign from a string
		void set(const String& pattern, bool wildcard_pattern = false);

		///	Assign to another instance
		void get(RegularExpression& regular_expression) const;
		//@}

		/**	@name	Accessors
		*/
		//@{

		///	Get the expression pattern.
		const String& getPattern() const;

		///	Count subexpressions.
		Size countSubexpressions() const;

		/**	Match a text with a given pattern.
		@param text to process
		@param pattern to compare with
		@param compile_flags ?????
		@param execute_flags ?????
		@exception NullPointer if <tt>text</tt> or <tt>pattern</tt> are NULL
		*/
		static bool match(const char* text, const char* pattern,
						  int compile_flags = 0 | REG_EXTENDED | REG_NOSUB, int execute_flags = 0);

		/**	Match a text with this regular expression.
		@param text to process
		@param from index in the string to start the matching
		@param execute_flags ?????
		*/
		bool match(const String& text, Index from = 0, int execute_flags = 0) const;

		/**	Match a substring with this regular expression.
		@param text to process
		@param from index in the substring to start the matching
		@param execute_flags ?????
		*/
		bool match(const Substring& text, Index from = 0, int execute_flags = 0) const;

		/**	Match a C-String with this regular expression.
		@param text to process
		@param execute_flags ?????
		*/
		bool match(const char* text, int execute_flags = 0) const;

		/**	Find this expression in a string
		@param from index in the string to start the matching
		@param found the result is stored as a substring here
		@param execute_flags ?????
		*/
		bool find(const String& text, Substring& found,
				  Index from = 0, int execute_flags = 0) const;

		/**	Find this expression in a string
		@param text to process
		@param subexpressions the results are stored here
		@param from index in the string to start the matching		
		@param execute_flags ?????
		*/
		bool find(const String& text, vector<Substring>& subexpressions,
				  Index from = 0, int execute_flags = 0) const;

		//@}
		/**	@name	Predicates
		*/
		//@{

		/**	Test if expression is empty.
		*/
		bool isEmpty() const;

		/**	Equality operator
		*/
		bool operator == (const RegularExpression& regular_expression) const;

		/**	Inequality operator
		*/
		bool operator != (const RegularExpression& regular_expression) const;

		/**	Less operator
		*/
		bool operator < (const RegularExpression& regular_expression) const;

		/**	Less or equal operator
		*/
		bool operator <= (const RegularExpression& regular_expression) const;

		/**	Greater or equal operator
		*/
		bool operator >= (const RegularExpression& regular_expression) const;

		/**	Greater operator
		*/
		bool operator > (const RegularExpression& regular_expression) const;

		//@}
		/**	@name	Debugging and Diagnostics
		*/
		//@{

		/**	Test if instance is valid.
		*/
		virtual bool isValid() const;

		/**	Dump this instance to an ostream
		depth is normaly just used for internal use.
		@param s the ostream, default is the standard output
		@param depth the indentation depth of the output
		*/
		virtual void dump(std::ostream& s = std::cout, Size depth = 0) const;

		//@}
		/**	@name Storers
		*/
		//@{

		/**	output operator
		*/
		friend std::ostream& operator << (std::ostream& s, const RegularExpression& regular_expression);

		/**	input operator
		*/
		friend std::istream& operator >> (std::istream& s, RegularExpression& regular_expression);

		//@}

	private:

		void compilePattern_();

		void toExtendedRegularExpression_() ;

		regex_t regex_;

		String  pattern_;
		bool    valid_pattern_;
	};

	inline 
	void RegularExpression::set(const RegularExpression& regular_expression)
	{
		pattern_.set(regular_expression.pattern_);
		regfree(&regex_);
		compilePattern_();
	}

	inline 
	void RegularExpression::set(const String& pattern, bool wildcard_pattern) 
	{
		pattern_.set(pattern);

		if (wildcard_pattern == true) {
			toExtendedRegularExpression_();
		}
		regfree(&regex_);
		compilePattern_();
	}

	inline 
	RegularExpression& RegularExpression::operator = (const RegularExpression& expression) 
	{
		this->set(expression);
		return(*this);
	}


	inline 
	void RegularExpression::get(RegularExpression& regular_expression) const 
	{
		regular_expression.set(*this);
	}

	inline 
	const String& RegularExpression::getPattern() const 
	{
		return pattern_;
	}

	inline 
	Size RegularExpression::countSubexpressions() const 
	{
		if (valid_pattern_ == true) {
			return(Size)regex_.re_nsub;
		}

		return 0;
	}

	inline 
	void RegularExpression::clear() 
	{
		set(BALL_REGULAR_EXPRESSION_DEFAULT_PATTERN);
	}

	inline 
	void RegularExpression::destroy() 
	{
		clear();
	}

	inline
	bool RegularExpression::isEmpty() const 
	{
		return pattern_.isEmpty();
	}

	inline 
	bool RegularExpression::operator == (const RegularExpression& regular_expression) const 
	{
		return(pattern_ == regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::operator != (const RegularExpression& regular_expression) const 
	{
		return(pattern_ != regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::operator < (const RegularExpression& regular_expression) const 
	{
		return(pattern_ < regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::operator <= (const RegularExpression& regular_expression) const 
	{
		return(pattern_ <= regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::operator >= (const RegularExpression& regular_expression) const 
	{
		return(pattern_ >= regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::operator > (const RegularExpression& regular_expression) const 
	{
		return(pattern_ > regular_expression.pattern_);
	}

	inline 
	bool RegularExpression::isValid() const 
	{
		return(valid_pattern_ == true && pattern_.isValid());
	}

} // namespace BALL

#endif // BALL_DATATYPE_REGULAREXPRESSION_H
